
Object.defineProperty(exports, "__esModule", { value: true });
/**
 * 数据库
 * @param {String} [cName] 在indexeddb中叫集合名，websql中叫表名 default: _local_
 * @param {Array} [fields] 一个集合或表中的所有字段 default: []
 * @param {Number} [maxSize] 最大存储空间，默认 200M 即：200 * 1024 * 1024
 * @return {this}
 */
var log_1 = __webpack_require__(/*! ./../utils/log */ "./src/extra/utils/log.ts");
function WebDB(cName, fields, maxSize) {
    var _collections = {};
    if (Object.prototype.hasOwnProperty.call(_collections, cName)) {
        return _collections[cName];
    }
    var db;
    cName = cName || '_local_';
    fields = fields || [];
    maxSize = maxSize || 200 * 1024 * 1024;
    try {
        db = new WebDB.IndexedDB(cName, fields, maxSize);
    }
    catch (e) {
        log_1.default.error('WebDB::create fail exception:' + e);
        return null;
    }
    return (_collections[cName] = db);
}
/**
 * 这里是indexeddb的封装
 * 特殊情况下，该封装会抛出错误
 * 错误代码，100-199为数据库错误，200-299为事务错误，300-399为对象模型（sql中的表），400-499为索引错误，500-599为游标错误
 *
 */
(function (global) {
    /**
     * 继承
     * @param  {function} sub      子类
     * @param  {function} super    超类
     * @param  {object | undefined} property 对原型的增强对象
     */
    function extend(sub, sup, property) {
        var proto = Object.create(sup.prototype);
        Object.keys(property).forEach(function (key) {
            proto[key] = property[key];
        });
        proto.constructor = sub;
        sub.prototype = proto;
    }
    //简单版的promise对象
    function Promise() {
        this._cbArray = [];
        this.state = 'waiting'; //有waiting和ready两个状态
    }
    Promise.prototype = {
        /**
         * 把方法加入队列
         * @param  {Function} cb 回调方法
         * @return {object} 返回this
         */
        done: function (cb) {
            if (this.state === 'waiting') {
                this._cbArray.push(cb.bind(this));
            }
            else {
                cb.call(this);
            }
            return this;
        },
        /**
         * 把对象标识为已准备,并把队列方法执行一遍
         * @return {object} 返回this
         */
        resolve: function () {
            this.state = 'ready';
            this._cbArray.forEach(function (val) {
                val();
            });
            this._cbArray = [];
            return this;
        }
    };
    var indexedDB = window.indexedDB || window.msIndexedDB || window.mozIndexedDB || window.webkitIndexedDB, IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction, IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange, IDBCursor = window.IDBCursor || window.webkitIDBCursor, DBPrefix = '_dx_', //数据库名字
    indexName = 'time', DBSetting = {
        key: "_id",
        options: {
            keyPath: "_id"
        }
    }, //出事数据库设置
    consts = {
        'READ_ONLY': 'readonly',
        'READ_WRITE': 'readwrite',
        'VERSION_CHANGE': 'versionchange',
        'NEXT': 'next',
        'NEXT_NO_DUPLICATE': 'nextunique',
        'PREV': 'prev',
        'PREV_NO_DUPLICATE': 'prevunique'
    };
    /**
     * 抛出异常
     * todo 修改抛出异常方法，使其更具通用性
     * @param  {object} event indexeddb的事件对象
     */
    function _throwEventError(idbError) {
        // if (error) {
        //     var error: any = new Error(idbError.message);
        //     error.code = idbError.code;
        // } else {
        //     var error: any = new Error('idb error');
        //     error.code = 1000;
        // }
        // throw error;
        log_1.default.error('Web SDK DB 存储异常', idbError);
    }
    /**
     * 数据库
     * @param {String} [cName] 在indexeddb中叫集合名，websql中叫表名 default: _local_
     * @param {Array} [fields] 一个集合或表中的所有字段 default: []
     * @param {Number} [maxSize] 最大存储空间，默认 200M 即：200 * 1024 * 1024
     * @return {this}
     * @constructor
     */
    function IndexedDB(cName, fields, maxSize) {
        Promise.call(this);
        this.cName = cName || '_local_'; //对象空间名字
        this.DBName = DBPrefix + this.cName; //数据库名字
        this.fields = fields || '';
        this.maxSize = maxSize || 200 * 1024 * 1024;
        // this.objectStore;   //对象空间
        // this.DB;            //数据库
        this._create();
        return this;
    }
    extend(IndexedDB, Promise, {
        /**
         * 根据给定的存储数据，组装一个表/集合的所有字段
         * @param {Object|Any} obj fields为空时可以是任意一个数据
         * @return {String}
         * @private
         */
        _mapFields: function (obj) {
            var fields = this.fields, len = fields.length, i = 0, storeObj = {};
            if (!obj) {
                return null;
            }
            // 为空时，相当于默认数据库
            if (len === i) {
                storeObj = obj;
            }
            else {
                while (i < len) {
                    if (Object.hasOwnProperty.call(obj, fields[i])) {
                        storeObj[fields[i]] = obj[fields[i]] == null ? '' : obj[fields[i]];
                    }
                    i++;
                }
            }
            return storeObj;
        },
        /**
         * 创建数据库连接
         * @return {[type]} [description]
         */
        _create: function () {
            var request = indexedDB.open(this.DBName, 1);
            request.onsuccess = function (event) {
                this.DB = event.target.result;
                //监听版本改变，防止版本并发问题
                this.DB.onversionchange = function (event) {
                    this.DB.close();
                    _throwEventError({ code: 101, message: 'database conflict!' });
                }.bind(this);
                this.resolve();
            }.bind(this);
            request.onerror = function (event) {
                _throwEventError(event.target.error);
            }.bind(this);
            request.onupgradeneeded = function (event) {
                // 建立对象空间
                var os = event.target.result.createObjectStore(this.cName, DBSetting.options);
                os.createIndex(indexName, indexName, { unique: false });
            }.bind(this);
        },
        /**
         * 获取对象空间
         * @private
         */
        _getOs: function () {
            var transaction = this.DB.transaction([this.cName], consts.READ_WRITE);
            transaction.oncomplete = function (event) {
            };
            transaction.onerror = function (event) {
                _throwEventError(event.target.error);
            };
            this.objectStore = transaction.objectStore(this.cName);
        },
        /**
         * 处理方法，支持get, add和delete
         * @param  {string} method    方法名，支持get和delete
         * @param  {string} key       键值
         * @param  {function} onSuccess 成功回调
         * @param  {function} onFail    失败回调
         */
        _process: function (method, key, onSuccess, onFail) {
            this.done(function () {
                this._getOs();
                var request = this.objectStore[method](key);
                request.onerror = function (event) {
                    onFail && onFail(event.target.error);
                };
                request.onsuccess = function (event) {
                    var data = event.target.result;
                    onSuccess && onSuccess(this._mapFields(data));
                }.bind(this);
            });
        },
        /**
         * 批处理方法，支持get和delete,remove
         * @param  {string} method    方法类型，可为get和delete
         * @param  {array} params       参数数组
         * @param  {function} onSuccess 成功回调
         * @param  {function} onFail    失败回调
         */
        _batchProcess: function (method, params, onSuccess, onFail) {
            this.done(function () {
                var _this = this;
                var result = {}, count = params.length, isError = false;
                this._getOs();
                var complete = function () {
                    if (isError) {
                        onFail && onFail(result);
                    }
                    else {
                        onSuccess && onSuccess(result);
                    }
                };
                params.forEach(function (val, index) {
                    var request = _this.objectStore[method](val);
                    request.onerror = function failCb(event) {
                        result[val] = null;
                        isError = true;
                        if (--count === 0) {
                            complete();
                        }
                    };
                    request.onsuccess = function (event) {
                        result[val] = _this._mapFields(event.target.result) || true;
                        if (--count === 0) {
                            complete();
                        }
                    };
                });
            });
        },
        /**
         * 获取单个数据
         * @param {String|Number} key
         * @param {Function} onSuccess
         * @param {Function} onFail
         */
        get: function (key, onSuccess, onFail) {
            this._process('get', key, onSuccess, onFail);
        },
        /**
         * 批量获取数据
         * @param {Array} keys
         * @param {Function} onSuccess
         * @param {Function} onFail
         */
        getBatch: function (keys, onSuccess, onFail) {
            this._batchProcess('get', keys, onSuccess, onFail);
        },
        /**
         * 插入单个数据，插入时需要通过key去判断是否存在之前数据
         * @param {String|Number} key
         * @param {Object} value
         * @param {Function} onSuccess
         * @param {Function} onFail
         * @return
         */
        set: function (key, value, onSuccess, onFail) {
            var data = this._mapFields(value);
            data[DBSetting.key] = key;
            if (!data[indexName])
                data[indexName] = value[indexName] ? value[indexName] : Date.now();
            this._process('put', data, onSuccess, onFail);
        },
        /**
         * 批量插入一组数据
         * @param {Object} dataObject
         * @param {Function} onSuccess
         * @param {Function} onFail
         */
        setBatch: function (dataObject, onSuccess, onFail) {
            var _this = this;
            var keys = Object.keys(dataObject), params = [];
            keys.forEach(function (val) {
                var data = _this._mapFields(dataObject[val]);
                if (!data[indexName])
                    data[indexName] = val[indexName] ? val[indexName] : Date.now();
                data[DBSetting.key] = val;
                params.push(data);
            });
            this._batchProcess('put', params, onSuccess, onFail);
        },
        /**
         * 删除一项数据
         * @param {String|Number} key
         * @param {Function} onSuccess
         * @param {Function} onFail
         */
        remove: function (key, onSuccess, onFail) {
            this._process('delete', key, onSuccess, onFail);
        },
        /**
         * 批量删除一组数据
         * @param {Array} keys
         * @param {Function} onSuccess
         * @param {Function} onFail
         */
        removeBatch: function (keys, onSuccess, onFail) {
            this._batchProcess('delete', keys, onSuccess, onFail);
        },
        /**
         * 获取所有的数据
         * @param {Function} onSuccess
         * @param {Function} onFail
         */
        all: function (onSuccess, onFail) {
            var result = {};
            this.done(function () {
                var _this = this;
                this._getOs();
                var request = this.objectStore.index(indexName).openCursor();
                request.onsuccess = function (event) {
                    var cursor = event.target.result;
                    if (cursor) {
                        result[cursor.value[DBSetting.key]] = _this._mapFields(cursor.value);
                        cursor.continue();
                    }
                    else {
                        onSuccess && onSuccess(result);
                    }
                };
                request.onerror = function (event) {
                    onFail && onFail(event.target.error);
                };
            });
        },
        /**
         * 清空所有数据
         * @param {Function} onSuccess
         * @param {Function} onFail
         */
        clear: function (onSuccess, onFail) {
            this._process('clear', null, onSuccess, onFail);
        },
        /**删除或创建表
         * @param {Function} onSuccess
         * @param {Function} onFail
         * 删除表,indexeddb只能在更新数据库版本的时候才能
         */
        delete: function (onSuccess, onFail) {
            this.clear(onSuccess, onFail);
        },
        /**
         * 过滤内容
         * @param {Function} fn 过滤条件
         * @param {Function} onSuccess 成功回调
         * @param {Function} onFail 失败回调
         * @param {number} after 开始时间，表示帅选出 跟新时间晚于该时间 的数据；如果数据有time字段，则找出time大于等于该时间的数据
         * @param {number} before 结束时间，表示数据 更新时间早于该时间 的数据；如果数据有time字段，则找出time小于该时间的数据
         * @param {number} limit 数目上限
         */
        filter: function (options) {
            var result = {};
            var before = options.before ? options.before : Date.now();
            var after = options.after ? options.after : (new Date(0)).getTime();
            var fn = options.fn ? options.fn : function () { return true; };
            var limit = options.limit ? options.limit : Number.MAX_VALUE;
            var num = 0;
            this.done(function () {
                var _this = this;
                this._getOs();
                var request = this.objectStore.index(indexName).openCursor(IDBKeyRange.bound(after, before, true), 'prev');
                request.onsuccess = function (event) {
                    var cursor = event.target.result, data;
                    if (cursor && num < limit) {
                        data = _this._mapFields(cursor.value);
                        /*if(fn(data)) result[cursor.value[DBSetting.key]] = data;
                        num++;*/
                        if (fn(data)) {
                            result[cursor.value[DBSetting.key]] = data;
                            num++;
                        }
                        cursor.continue();
                    }
                    else {
                        options.onSuccess && options.onSuccess(result);
                    }
                };
                request.onerror = function (event) {
                    options.onFail && options.onFail(event.target.error);
                };
            });
        }
    });
    global.IndexedDB = IndexedDB;
})(WebDB);
exports.default = WebDB;


//# sourceURL=webpack://MTDX/./src/extra/dao/web-db.ts?